home *** CD-ROM | disk | FTP | other *** search
- /*
- * WADWHAT.C - print the contents of a DOOM WAD file
- *
- * by Randall R. Spangler
- *
- * $Revision: 1.7 $ $Date: 1994/08/22 03:51:43 $
- *
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <dos.h>
- #include <dir.h>
-
- struct s_thing { /* Thing data */
- int x, y; /* Coordinates */
- int facing; /* Facing, in degrees */
- int type; /* Type of thing */
- int attr; /* Thing attributes */
- };
- typedef struct s_thing THING;
-
- /***************************************************************************/
-
- char contents[10][9] = /* Valid sub-entry names for a level */
- {"THINGS", "LINEDEFS", "SIDEDEFS", "VERTEXES", "SEGS", "SSECTORS",
- "NODES", "SECTORS", "REJECT", "BLOCKMAP"};
-
- char itemline[] = "\t%-20s %5d %5d %5d %5d + %5d\n"; /* Line of text for an
- * item */
-
- /***************************************************************************/
-
- int isbrief = 0; /* If non-zero, is the skill level we're
- * printing brief stats on */
- int battr = 0; /* Matching attribute byte for brief printout */
-
- int battrarry[5] = {0x01, 0x01, 0x02, 0x04, 0x04}; /* Attribute bytes vs.
-
- * skill level */
-
- FILE *savefile; /* WAD file whose things we're looking at */
- long savefilepos; /* Save position in WAD file (where we were
- * before we started looking at THINGS) */
- THING *th; /* Thing data for a level */
- int numth = 0; /* Number of things */
-
- char buf[256];
-
- /***************************************************************************/
-
- int countth(int type, int attr)
- {
- /* Returns the number of things of the specified type with at least one
- * matching attribute bit. */
-
- THING *t = th;
- int n = 0;
- int i;
-
- for (i = 0; i < numth; i++) { /* Search all things */
- if ((t->type == type) && ((t->attr) & attr))
- n++; /* Found a match */
- t++; /* Advance to next thing */
- }
-
- return n; /* Return match count */
- }
-
- /***************************************************************************/
-
- int *countdiff(int type, int *dest)
- {
- /* Counts the number of things of the specified type at each difficulty
- * level. dest[0]=L12, dest[1]=L3, dest[2]=L45, dest[3]=multiplayer
- * only. Returns a pointer to the destination array, or NULL if error. */
-
- THING *t = th;
- int i;
-
- dest[0] = dest[1] = dest[2] = dest[3] = 0; /* Clear destination array */
-
-
- for (i = 0; i < numth; i++) { /* Search all things */
- if (t->type == type) { /* Matched type */
- if (t->attr & 0x0001)
- dest[0]++;
- if (t->attr & 0x0002)
- dest[1]++;
- if (t->attr & 0x0004)
- dest[2]++;
- if (t->attr & 0x00010)
- dest[3]++;
- }
- t++; /* Advance to next thing */
- }
-
- return dest; /* Return match count */
- }
-
- /***************************************************************************/
-
- int prtth(int type, char *desc)
- {
- /* Prints the description and number of matching things at each
- * difficulty level. Returns zero if error. */
-
- int nd[4]; /* Numbers at each difficulty level */
-
- countdiff(type, nd);
-
- if (nd[0] + nd[1] + nd[2] + nd[3] == 0)
- return 0; /* No matching things */
-
- printf(itemline, desc, nd[0], nd[0], nd[1], nd[2], nd[3]);
- return 1;
- }
-
- /***************************************************************************/
-
- int *addcountweighted(int type, int *dest, int weight)
- {
- /* Similar to countdiff(), but adds <weight> times the counts vs.
- * difficulty to the destination array instead of just setting it to the
- * match counts. Returns NULL if error. */
-
- int nd[4];
- int i;
-
- countdiff(type, nd); /* Count the matches */
-
- for (i = 0; i < 4; i++)
- dest[i] += weight * nd[i]; /* Add a weighted result */
-
- return dest;
- }
-
- /***************************************************************************/
- /***************************************************************************/
-
- int loadthings(FILE * f, long offs, long len)
- {
- /* Loads a map's THINGS data at offset <offs>, length <len>. Returns
- * zero if error. */
-
- savefile = f; /* Save WAD file handle */
- savefilepos = ftell(f); /* Save position in WAD file */
-
- fseek(f, offs, SEEK_SET);
- th = (THING *) malloc(len);
- if (!th) {
- fprintf(stderr, "Not enough memory to hold THINGS\n");
- return 0;
- }
- fread(th, 1, len, f);
- numth = len / 10;
-
- return 1; /* Success */
- }
-
- int freethings(void)
- {
- /* Frees a map's THINGS data loaded by loadthings(). Returns zero if
- * error. */
-
- free(th);
- numth = 0;
-
- fseek(savefile, savefilepos, SEEK_SET);
-
- return 1; /* Success */
- }
-
- /***************************************************************************/
- /***************************************************************************/
-
- /* If there is at least one thing with id <no>, print the description of the
- * thing and the number present at each skill level. */
- #define PRINTITEM(desc,arry)\
- if((arry)[0]+(arry)[1]+(arry)[2]+(arry)[3])\
- printf(itemline,desc,(arry)[0],(arry)[0],(arry)[1],(arry)[2],(arry)[3])
-
- /* Same as above, but L1 is doubled (all ammo is doubled in skill level #1) */
- #define PRINTITEM2(desc,arry)\
- if((arry)[0]+(arry)[1]+(arry)[2]+(arry)[3])\
- printf(itemline,desc,2*(arry)[0],(arry)[0],(arry)[1],(arry)[2],(arry)[3])
-
- int countthings(void)
- {
- /* Counts the things in a level's THINGS data. Returns zero if error. */
-
- int nc[4]; /* Number of things counted at each skill
- * level */
- int wdam[4] = {0, 0, 0, 0}; /* Total weapon damage at each skill
- * level */
- float dratio[4] = {0, 0, 0, 0}; /* Damage ratio for
- * difficulty */
- int n, i;
-
- /** Player starts **/
-
- printf(" Play modes:\n");
-
- if (countth(1, 0x07)) /* Find player 1 start */
- printf("\tSingle player\n");
- n = 0;
-
- for (i = 1; i <= 4; i++) { /* Find player 1-4 starts */
- if (countth(i, 0x17))
- n++;
- }
- if (n > 1)
- printf("\tCooperative (%d player)\n", n);
-
- n = countth(11, 0x17); /* Find deathmatch starts */
- if (n)
- printf("\tDeathmatch (%d starts)\n", n);
-
- /** Monsters **/
-
- printf(" Bosses:\n");
- prtth(3003, "Baron");
- prtth(16, "Cyberdemon");
- prtth(7, "Spiderdemon");
-
- printf(" Monsters:\n");
- prtth(3004, "Trooper");
- prtth(9, "Sergeant");
- prtth(3001, "Imp");
- prtth(3002, "Demon");
- prtth(58, "Spectre");
- prtth(3006, "Lost soul");
- prtth(3005, "Cacodemon");
-
- printf(" Weapons:\n");
- prtth(2001, "Shotgun");
- prtth(2002, "Chaingun");
- prtth(2003, "Rocket launcher");
- prtth(2004, "Plasma gun");
- prtth(2006, "BFG-9000");
- prtth(2005, "Chainsaw");
-
- printf(" Equipment:\n");
- prtth(8, "Backpack");
- prtth(2022, "Invulnerability");
- prtth(2023, "Berserk");
- prtth(2024, "Invisibility");
- prtth(2025, "Radiation suit");
- prtth(2026, "Computer map");
- prtth(2027, "Lite amp goggles");
-
- printf(" Expendibles:\n");
-
- nc[0] = nc[1] = nc[2] = nc[3] = 0;
- addcountweighted(2002, nc, 20); /* Chainguns */
- addcountweighted(2007, nc, 10); /* Clips */
- addcountweighted(2048, nc, 50); /* Boxes of ammo */
- addcountweighted(8, nc, 10); /* Backpacks */
- addcountweighted(3004, nc, 5); /* Troopers */
- PRINTITEM2("Bullets", nc);
- for (i = 0; i < 4; i++)
- wdam[i] += nc[i]; /* Accumulate damage */
-
- nc[0] = nc[1] = nc[2] = nc[3] = 0;
- addcountweighted(2001, nc, 8); /* Shotguns */
- addcountweighted(2008, nc, 4); /* Shells */
- addcountweighted(2049, nc, 20); /* Boxes of shells */
- addcountweighted(8, nc, 4); /* Backpacks */
- addcountweighted(9, nc, 4); /* Sergeants */
- PRINTITEM2("Shells", nc);
- for (i = 0; i < 4; i++)
- wdam[i] += 7 * nc[i]; /* Accumulate damage */
-
- nc[0] = nc[1] = nc[2] = nc[3] = 0;
- addcountweighted(2003, nc, 2); /* Rocket launchers */
- addcountweighted(2010, nc, 1); /* Rockets */
- addcountweighted(2046, nc, 5); /* Boxes of rockets */
- addcountweighted(8, nc, 1); /* Backpacks */
- PRINTITEM2("Rockets", nc);
- for (i = 0; i < 4; i++)
- wdam[i] += 20 * nc[i]; /* Accumulate damage */
-
- nc[0] = nc[1] = nc[2] = nc[3] = 0;
- addcountweighted(2004, nc, 40); /* Plasma guns */
- addcountweighted(2006, nc, 40); /* BFG-9000's */
- addcountweighted(17, nc, 20); /* Cell packs */
- addcountweighted(2047, nc, 100); /* Cell charges */
- addcountweighted(8, nc, 20); /* Backpacks */
- PRINTITEM2("Cells", nc);
- for (i = 0; i < 4; i++)
- wdam[i] += 2 * nc[i]; /* Accumulate damage */
-
- nc[0] = nc[1] = nc[2] = nc[3] = 0;
- addcountweighted(2018, nc, 100); /* Armor */
- addcountweighted(2019, nc, 200); /* Super armor */
- addcountweighted(2015, nc, 1); /* Armor bonuses */
- PRINTITEM2("Armor points", nc);
-
- nc[0] = nc[1] = nc[2] = nc[3] = 0;
- addcountweighted(2011, nc, 10); /* Stimpacks */
- addcountweighted(2012, nc, 25); /* Medikits */
- addcountweighted(2013, nc, 100); /* Soul spheres */
- addcountweighted(2023, nc, 100); /* Berserk strength */
- addcountweighted(2014, nc, 1); /* Health bonuses */
- PRINTITEM2("Health points", nc);
-
- prtth(2035, "Barrels");
-
- /* Calculate difficulty based on damage we can do vs. damage required to
- * kill all the monsters */
-
- printf(" Difficulty:\n");
-
- nc[0] = nc[1] = nc[2] = nc[3] = 0;
- addcountweighted(3004, nc, 2); /* Troopers */
- addcountweighted(9, nc, 3); /* Sergeants */
- addcountweighted(3001, nc, 6); /* Imps */
- addcountweighted(3002, nc, 15); /* Demons */
- addcountweighted(58, nc, 15); /* Spectres */
- addcountweighted(3006, nc, 10); /* Lost souls */
- addcountweighted(3005, nc, 40); /* Cacodemons */
- addcountweighted(3003, nc, 100); /* Barons */
- addcountweighted(16, nc, 400); /* Cyberdemons */
- addcountweighted(7, nc, 300); /* Spiderdemons */
- PRINTITEM("Total monster hp", nc);
- PRINTITEM2("Max ammo damage", wdam);
-
- for (i = 0; i < 4; i++) {
- if (!wdam[i])
- continue;
- dratio[i] = (float) nc[i] / (float) wdam[i];
- }
- printf("\t%-20s %0.3f %0.3f %0.3f %0.3f + %0.3f\n", "RATIO", 0.5 * dratio[0], dratio[0], dratio[1], dratio[2], dratio[3]);
-
- /*** Return success ***/
-
- return 1;
- }
-
- /***************************************************************************/
-
- /* Item count */
- #define COB(item) countth(item,battr)
- /* Print a character if the item is present */
- #define PRB0(item,char) printf("%c",(COB(item)?(char):'.'))
- /* Print item count, one digit */
- #define PRB1(item) {n=COB(item);printf((n>9?"+ ":"%d "),n);}
- /* Print item count, two digits */
- #define PRB2(item) {n=COB(item);printf((n>99?"++ ":"%2d "),n);}
-
- int countbriefly(void)
- {
- /* Counts the things in a level, with one-line output format. Returns
- * zero if error. */
-
- long wdam = 0; /* Total weapon damage */
- long mhp = 0; /* Total monster hit points */
- float dratio; /* Damage ratio */
-
- int n, i;
-
- /*** Player starts ***/
-
- n = 0;
- for (i = 1; i <= 4; i++) { /* Find player 1-4 starts */
- if (countth(i, 0x17))
- n++;
- }
- printf(" %d %2d ", n, COB(11)); /* Find deathmatch starts */
-
- /*** Monsters ***/
-
- /* Bosses */
- PRB2(3003);
- PRB1(16);
- PRB1(7);
-
- /* Monsters */
- printf(" ");
- PRB2(3004);
- PRB2(9);
- PRB2(3001);
- PRB2(3002);
- PRB2(58);
- PRB2(3006);
- PRB2(3005);
-
- /* Weapons */
- putchar(' ');
- PRB0(2005, '1');
- putchar('2');
- PRB0(2001, '3');
- PRB0(2002, '4');
- PRB0(2003, '5');
- PRB0(2004, '6');
- PRB0(2006, '7');
-
- /* Equipment */
- printf(" ");
- PRB0(8, 'B');
- PRB0(2022, 'V');
- PRB0(2023, 'S');
- PRB0(2024, 'I');
- PRB0(2025, 'R');
- PRB0(2026, 'A');
- PRB0(2027, 'L');
-
- /*** Calculate damage ratio ***/
-
- /** Ammo from all sources **/
-
- n = 20 * COB(2002) + 10 * COB(2007) + 50 * COB(2048) + 10 * COB(8) + 5 * COB(3004);
- wdam += n; /* Bullets */
-
- n = 8 * COB(2001) + 4 * COB(2008) + 20 * COB(2049) + 4 * COB(8) + 4 * COB(9);
- wdam += 7 * n; /* Shells */
-
- n = 2 * COB(2003) + COB(2010) + 5 * COB(2046) + COB(8);
- wdam += 20 * n; /* Rockets */
-
- n = 40 * COB(2004) + 40 * COB(2006) + 20 * COB(17) + 100 * COB(2047) + 20 * COB(8);
- wdam += 2 * n; /* Cell packs */
-
- /** Monster hit points **/
-
- mhp = 2 * COB(3004) + 3 * COB(9) + 6 * COB(3001) + 15 * COB(3002) + 15 * COB(58)
- + 10 * COB(3006) + 40 * COB(3005) + 100 * COB(3003) + 400 * COB(16) + 300 * COB(7);
-
- dratio = (float) mhp / (float) wdam;
- if (isbrief == 1)
- dratio *= 0.5; /* Twice as much ammo in easiest
- * level */
-
- printf(" %0.3f\n", dratio);
-
- /*** Return success ***/
-
- return 1;
-
- }
-
- /***************************************************************************/
-
- int handlepwad(char *fname)
- {
- /* Handles a PWAD file. Returns zero if error. */
-
- int ispwad = 0; /* Are we a PWAD? (or an IWAD) */
-
- long ndirent; /* Number of entries in WAD directory */
- long diroffs; /* Offset of directory in WAD file */
-
- long eoffs, elen; /* Offset and length of a directory entry */
- char ename[9] = "entrynam"; /* Name of the entry */
- int episode = 0, mission = 0; /* Current episode and
- * mission */
- FILE *f;
- int i, j;
-
- /*** Open the PWAD file ***/
-
- f = fopen(fname, "rb");
- if (!f) {
- fprintf(stderr, "Can't open file %s\n", fname);
- return 0;
- }
- /*** Read the header ***/
-
- fread(buf, sizeof(char), 4, f);
- if (!strncmp(buf, "IWAD", 4)) {
- ispwad = 0;
- } else if (!strncmp(buf, "PWAD", 4)) {
- ispwad = 1;
- } else {
- printf("%s is not a DOOM WAD file\n", fname);
- fclose(f);
- return 0;
- }
-
- if (!isbrief) { /* Start a new filename in the output */
- printf("============================================================\n");
- printf("%cWAD FILE %s:\n", (ispwad ? 'P' : 'I'), fname);
- }
- fread(&ndirent, sizeof(long), 1, f);/* Number of entries in WAD dir */
- fread(&diroffs, sizeof(long), 1, f);/* Offset of directory in WAD */
-
- /*** Print the WAD directory ***/
-
- fseek(f, diroffs, SEEK_SET); /* Go to the directory */
-
- for (i = 0; i < ndirent; i++) {
-
- /** Read entry **/
-
- fread(&eoffs, sizeof(long), 1, f); /* Offset of entry's data */
- fread(&elen, sizeof(long), 1, f); /* Length of entry's data */
- fread(&ename, sizeof(char), 8, f); /* Name of entry */
-
- /** Keep track of which mission we're looking at **/
-
- if (ename[0] == 'E' && isdigit(ename[1]) && ename[2] == 'M' &&
- isdigit(ename[3]) && ename[4] == '\0') {
- episode = ename[1] - '0';
- mission = ename[3] - '0';
-
- if (isbrief) { /* One-line output */
- printf("%-12.12s E%dM%d", fname, episode, mission);
- } else { /* Verbose output */
- printf("------------------------------------------------------------\n");
- printf("EPISODE %d MISSION %d L1 L2 L3 L45 + multi\n", episode, mission);
- printf("------------------------------------------------------------\n");
- }
- }
- /** If entry is part of a level, print it **/
-
- for (j = 0; j < 10; j++) {
- if (!strcmp(ename, contents[j]))
- break; /* Matched valid contents for a level */
- }
-
- if (j == 10) { /* Didn't match level contents */
- episode = mission = 0; /* No longer in a level */
- continue; /* Not valid part of a level */
- }
- if (j == 0) { /* Things */
- if (!loadthings(f, eoffs, elen)) /* Load things */
- continue;
- if (isbrief)
- countbriefly(); /* Print brief counts */
- else
- countthings(); /* Print verbose counts */
- freethings(); /* Free array, restore original file
- * position */
- }
- }
-
- /*** Close the file and return success ***/
-
- fclose(f);
- return 1;
- }
-
- /***************************************************************************/
- /***************************************************************************/
-
- int main(int argc, char *argv[])
- {
-
- struct ffblk ff;
- int i;
-
- /*** Make sure we've been given a filename ***/
-
- printf("WADWHAT 1.0 by Randall R. Spangler (rspangle@micro.caltech.edu)\n");
-
- if (argc < 2) {
- printf("Prints the contents of a WAD file or files.\n");
- printf("Usage:\n\twadwhat [-Bn[M]] file1 [file2 ...]\n");
- printf("\n\t\t-Bn\tbrief contents at skill level n\n");
- printf("\t\t-BnM\tbrief contents at skill level n, multiplayer\n");
- return 1;
- }
- /*** Match all wildcards ***/
-
- for (i = 1; i < argc; i++) {
-
- /** See if we're an option **/
-
- if (!strnicmp(argv[i], "-B", 2)) { /* Print briefly */
- isbrief = atoi(argv[i] + 2);/* Extract skill level */
- printf("File Map Play Bosses Monsters Weapons Equip RATIO\n");
- printf("-------------------c-de--ba-c-s--tr-se-im-de-sp-lo-ca--cpscrpb--bvsiral-------\n");
- battr = battrarry[isbrief - 1]; /* Matching attributes for
- * brief printout */
- if (toupper(argv[i][3]) == 'M')
- battr |= 0x10; /* Add in multi-player stuff */
- continue;
- }
- /** Make sure at least one matching file exists **/
-
- if (findfirst(argv[i], &ff, FA_ARCH)) { /* No match for wildcard */
- fprintf(stderr, "Can't find file matching %s\n", argv[i]);
- continue;
- }
- /** Handle all the matching files **/
-
- do {
- handlepwad(ff.ff_name);
- } while (!findnext(&ff));
- }
-
- /*** Return success ***/
-
- return 0;
- }
-
- /***************************************************************************/
- /***************************************************************************/
-